<?php

namespace CMB\Http;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Middleware;

class Request
{
    /**
     * http timeout
     * @var int
     */
    protected $timeout = 3;

    /**
     * url
     * @var
     */
    protected $url;

    /**
     * debug
     * @var bool
     */
    protected $debug = false;

    /**
     * header
     * @var array
     */
    protected $headers = [];

    /**
     * http method
     * @var string
     */
    protected $method = 'GET';

    /**
     * can async
     * @var bool
     */
    protected $async = false;

    /**
     * get method submit param
     * @var array
     */
    protected $getParam = [];

    /**
     * json,body,formData
     * @var string $format
     */
    protected $format = '';

    /**
     * post method submit param
     * @var array
     */
    protected $body = [];
    protected $json = [];
    protected $formData = [];

    /**
     * @var string
     */
    protected $cookie;

    /**
     * @var string
     */
    protected $proxy;

    private $option;

    protected $logsDir;

    protected $logTip = '';

    /**
     * @param int $timeout
     * @return Request
     */
    public function setTimeout(int $timeout): Request
    {
        $this->timeout = $timeout;
        return $this;
    }

    /**
     * @param $url
     * @return $this
     * @author xis
     */
    public function setUrl($url): Request
    {
        $this->url = $url;
        return $this;
    }

    /**
     * @param bool $debug
     * @return Request
     */
    public function setDebug(bool $debug): Request
    {
        $this->debug = $debug;
        return $this;
    }

    /**
     * @param array $headers
     * @return $this
     * @author xis
     */
    public function setHeaders(array $headers): Request
    {
        $this->headers = $headers;
        return $this;
    }

    /**
     * @return array
     */
    public function getHeaders(): array
    {
        return $this->headers;
    }

    /**
     * @param string $method
     * @return $this
     * @author xis
     */
    public function setMethod(string $method): Request
    {
        $this->method = $method;
        return $this;
    }

    /**
     * @param bool $async
     * @return $this
     * @author xis
     */
    public function setAsync(bool $async): Request
    {
        $this->async = $async;
        return $this;
    }

    /**
     * @param array $getParam
     * @return $this
     * @author xis
     */
    public function setGetParam(array $getParam): Request
    {
        $this->getParam = $getParam;
        return $this;
    }

    /**
     * @return string
     */
    public function getFormat(): string
    {
        return $this->format;
    }

    public function getGetParam(): array
    {
        return $this->getParam;
    }

    /**
     * @param array|string $body
     * @return $this
     * @author xis
     */
    public function setBody($body): Request
    {
        $this->body = $body;
        return $this;
    }

    /**
     * @param array $json
     * @return $this
     * @author xis
     */
    public function setJson(array $json): Request
    {
        $this->json = $json;
        return $this;
    }

    /**
     * @param array $formData
     * @return $this
     * @author xis
     */
    public function setFormData(array $formData): Request
    {
        $this->formData = $formData;
        return $this;
    }

    /**
     * @param mixed $cookie
     */
    public function setCookie(string $cookie): Request
    {
        $this->cookie = $cookie;
        return $this;
    }

    /**
     * @param string $proxy
     */
    public function setProxy(string $proxy): void
    {
        $this->proxy = $proxy;
    }

    public function setLogsDir($dir)
    {
        $this->logsDir = rtrim($dir, '/') . '/';
    }

    /**
     * @param string $logTip
     */
    public function setLogTip(string $logTip): void
    {
        $this->logTip = $logTip;
    }

    /**
     * @return string
     */
    public function getLogTip(): string
    {
        return $this->logTip;
    }

    public function request(string $response, bool $returnUrl = false): Response
    {
        $this->buildUrl();
        $this->buildMethod();
        $this->buildOptions();

        $uuid = sha1(uniqid());

        $this->requestLogs($uuid);
        $response = new $response;

        //-----
        //测试
//        var_dump($this->url);
//        var_dump($this->option);
//        $response->setBody('{"SYCOMRETZ":[{"ERRMSG":"","ERRCOD":"0000000","ERRDTL":""}],"EAISMYPDFZ":[{"RESKEY":"XFT-APA:EP000000001"}],"EAISMYPDFY":[{"CONFLG":"N","CONSEQ":""}]}');
//        $response->setCode('200');
//        $response->resolve();
//        return  $response;
        //------

        //直接返回跳转地址
        if ($returnUrl) {
            $response->setCode('200')
                ->setBody($this->url);
            return $response;
        }
        //接口请求
        try {

            $client = new Client();

            $result = $client->request($this->method, $this->url, $this->option);
            $body = $result->getBody()->getContents();

            $this->responseLogs($uuid, $body);

            $response->setCode($result->getStatusCode())
                ->setHeader($result->getHeaders())
                ->setBody($body)
                ->resolve();
            return $response;
        } catch (GuzzleException $e) {
            $response->setCode('500')
                ->setError($e->getMessage());
            return $response;
        }

    }

    private function buildUrl()
    {
        $this->method = strtolower($this->method);
        if ($this->method == 'get' and $this->getParam) {
            $this->url .= '?' . http_build_query($this->getParam);
        }
    }

    private function buildMethod()
    {
        if ($this->async) {
            $this->method .= 'Async';
        }
    }

    /**
     * 构建请求数据
     * @return void
     */
    private function buildOptions()
    {
        $this->option['verify'] = false;

        if ($this->headers) {
            $this->option['headers'] = $this->headers;
        }

        if ($this->body) {
            $this->option['body'] = $this->body;
        }

        if ($this->cookie) {
            $this->option['cookies'] = $this->cookie;
        }

        if ($this->timeout) {
            $this->option['connect_timeout'] = $this->timeout;
            $this->option['timeout'] = $this->timeout;
        }

        if ($this->debug) {
            $this->option['debug'] = $this->debug;
        }
        if ($this->formData) {
            $this->option['form_params'] = $this->formData;
        }
        if ($this->json) {
            $this->option['json'] = $this->json;
        }
        if ($this->proxy) {
            if (!strpos($this->proxy, '//')) {
                $this->proxy = 'http://' . $this->proxy;
            }

            $this->option['proxy'] = $this->proxy;
        }
    }

    private function requestLogs($uuid)
    {
        if (!$this->logsDir) {
            return;
        }

        $logs = date('Y-m-d H:i:s') . " REQUEST  " . $uuid . " ";
        if ($this->method == 'get') {
            $logs .= $this->url;
        } else {
            if ($this->option) {
                $logs .= json_encode($this->option, JSON_UNESCAPED_UNICODE);
            } else {
                $logs .= $this->url;
            }
        }

        $fileName = $this->logsDir . date('Ym');

        if (!is_dir($fileName)) {
            @mkdir($fileName, 755, true);
        }
        $file = date('Ymd') . '.logs';

        $urlLogs = date('Y-m-d H:i:s') . " URL      " . $uuid . " " . $this->logTip .' '. $this->url;

        file_put_contents($fileName . '/' . $file, $urlLogs . "\r\n", FILE_APPEND);
        file_put_contents($fileName . '/' . $file, $logs . "\r\n", FILE_APPEND);
    }

    private function responseLogs($uuid, $data)
    {
        if (!$this->logsDir) {
            return;
        }
        if (!$data) {
            $data = '';
        } elseif (is_array($data)) {
            $data = json_encode($data, JSON_UNESCAPED_UNICODE);
        } elseif (is_string($data)) {
            if (!json_decode($data)) {
                return;
            }
        }

        $logs = date('Y-m-d H:i:s') . " RESPONSE " . $uuid . " ";
        $logs .= $data;

        $fileName = $this->logsDir . date('Ym');

        if (!is_dir($fileName)) {
            @mkdir($fileName, 755, true);
        }

        $file = date('Ymd') . '.logs';
        file_put_contents($fileName . '/' . $file, $logs . "\r\n", FILE_APPEND);
    }
}